#ifndef __NVM_H
#define __NVM_H

#include "stdint.h"

#ifndef NULL
#define NULL 0
#endif

/**
 * @breif 智能擦除使能
 * @note 智能擦除会对要擦除的区域进行空白检测，然后决定是否要执行擦除
*/
#define NVM_INTELLIGENT_ERASE       0
/**
 * @breif 擦除校验使能
 * @note 使能后会检查要擦除的NVM区域是否擦除成功
*/
#define NVM_ERASE_VERIFY            0
/**
 * @breif 编程校验使能
 * @note 使能后会检查是否将要编程的数据正确编程到NVM中
*/
#define NVM_PROGRAM_VERIFY          0

/**
 * @breif 线程安全模式使能， 使能后需要实现OS的互斥信号量
 * @note 在中断里面调用本模块的NVM操作接口依旧是不安全的
 *       使能线程安全模式后，需要实现以下宏定义：
 *          NVM_OS_MUTEX_CREATE，
 *          NVM_OS_MUTEX_DELETE，
 *          NVM_OS_MUTEX_GIVE，
 *          NVM_OS_MUTEX_TAKE;
*/
#define NVM_OS_THREAD_SAFE_MODE     0

#if NVM_OS_THREAD_SAFE_MODE == 1

#include "sys.h"
#include "device_common.h"

/** @breif  填充本宏定义，实现创建一个互斥信号量，并将其句柄赋予mutex,创建成功返回0，创建失败返回-1 */
#define NVM_OS_MUTEX_CREATE(mutex)    NULL != (mutex = xSemaphoreCreateMutex()) ? 0 : -1
/** @breif  填充本宏定义，实现删除互斥信号量mutex, 无返回值 */
#define NVM_OS_MUTEX_DELETE(mutex)    vSemaphoreDelete(mutex)
/** @breif  填充本宏定义，实现释放互斥信号量mutex，释放成功返回0，释放失败返回-1 */
#define NVM_OS_MUTEX_GIVE(mutex)      pdTRUE == xSemaphoreGive(mutex) ? 0 : -1
/** @breif  填充本宏定义，实现获取互斥信号量mutex，获取成功返回0，获取失败返回-1 */
#define NVM_OS_MUTEX_TAKE(mutex)      pdTRUE == xSemaphoreTake(mutex, portMAX_DELAY) ? 0 : -1
#endif

typedef enum
{
    NVM_OK      = 0,            /* 操作正常 */
    NVM_ERR_INIT,               /* 初始化出错 */
    NVM_ERR_DEINIT,             /* 反初始化出错 */
    NVM_ERR_PROGRAM,            /* 编程出错 */
    NVM_ERR_ERASE,              /* 擦除出错 */
    NVM_ERR_READ,               /* 读取出错 */
    NVM_ERR_VERIFY,             /* 校验出错 */
    NVM_ERR_INVALID_ADDRESS     /* 无效地址 */
    
}nvm_status;

typedef struct
{
    struct
    {
        uint32_t    mem_base,       /* NVM基地址 */
                    mem_size,       /* NVM全片大小(Byte) */
                    size_of_sector; /* NVM扇区大小(Byte) */
        uint8_t     blank_value;    /* NVM空白值，本模块会根据此值来判断擦写的区域是否空白 */
    }dev_info;

    /* 初始化NVM */
    void        *(*init)(void);
    /* 反初始化NVM */
    int32_t     (*deinit)(void *h_dev);
    /* 从NVM指定地址读出数据 */
    int32_t     (*read)(void *h_dev, uint32_t addr, uint8_t *p_buf, uint32_t size);
    /* 擦除NVM指定扇区 */
    int32_t     (*erase_sector)(void *h_dev, uint32_t sector_base);
    /* 往指定地址编程指定数据 */
    int32_t     (*program)(void *h_dev, uint32_t addr, uint8_t *p_buf, uint32_t size);
}nvm_bsp_ops_t;


typedef struct
{
    void            *h_dev;             /* NVMBSP句柄 */
    nvm_bsp_ops_t   *p_bsp;             /* NVMBSP驱动接口 */
    uint8_t         *p_backup_buf;      /* 数据备份缓冲区 */

#if NVM_ERASE_VERIFY == 1 || NVM_ERASE_VERIFY == 1 || NVM_INTELLIGENT_ERASE == 1
    uint8_t         *p_readback_buf;    /* 数据读回缓冲区 */
#endif
    
#if NVM_OS_THREAD_SAFE_MODE == 1
    void            *os_mutex;          /* 互斥信号量句柄 */
#endif
}nvm_t;


/**
  * @brief  NVM初始化
  * @param  h_nvm: 要操作的NVM句柄.
  * @param  p_bsp: NVMBSP驱动接口
  * @param  p_backup_buf: 数据备份缓冲区，对同一擦除单位进行保留数据回写时使用，应设置不小于一个擦除单位（扇区）
  * @param  p_readback_buf: 数据读出缓冲区，擦除编程校验，空白检测时使用，应设置不小于一个擦除单位（扇区）
  * @retval 参考枚举类型nvm_status的定义
  */
nvm_status nvm_init(nvm_t *h_nvm,
    nvm_bsp_ops_t *p_bsp,
    uint8_t *p_backup_buf
#if NVM_ERASE_VERIFY == 1 || NVM_ERASE_VERIFY == 1 || NVM_INTELLIGENT_ERASE == 1
    ,uint8_t *p_readback_buf
#endif
);

/**
  * @brief  NVM反初始化
  * @param  h_nvm: 要操作的NVM句柄.
  * @retval 参考枚举类型nvm_status的定义
  */
nvm_status nvm_deinit(nvm_t *h_nvm);

/**
  * @brief  从NVM读取指定大小的数据到指定的缓冲区
  * @param  h_nvm: 要操作的NVM句柄.
  * @param  addr: 读取起始地址
  * @param  p_buf: 读取数据缓冲区
  * @param  size: 读取大小
  * @retval 参考枚举类型nvm_status的定义
  */
nvm_status nvm_read(nvm_t *h_nvm, uint32_t addr, uint8_t *p_buf, uint32_t size);

/**
  * @brief  擦除指定范围的数据
  * @param  h_nvm: 要操作的NVM句柄.
  * @param  addr: 擦除起始地址
  * @param  size：擦除大小
  * @retval 参考枚举类型nvm_status的定义
  */
nvm_status nvm_erase(nvm_t *h_nvm, uint32_t addr, uint32_t size);

/**
  * @brief  将缓冲区中指定大小的数据编程到NVM中
  * @param  h_nvm: 要操作的NVM句柄.
  * @param  addr: 编程起始地址
  * @param  p_buf: 编程数据缓冲区
  * @param  size: 编程大小
  * @retval none
  */
nvm_status nvm_program(nvm_t *h_nvm, uint32_t addr, uint8_t *p_buf, uint32_t size);

/**
  * @brief  将缓冲区中指定长度的数据更新到指定NVM的地址范围
  * @note   该接口为nvm_erase()与nvm_program()的二合一版本，完成先擦除指定地址范围然后将数据写入到该范围的操作
  * @param  h_nvm: 要操作的NVM句柄.
  * @param  addr: 更新起始地址
  * @param  p_buf: 更新数据缓冲区
  * @param  size: 更新大小
  * @retval none
  */
nvm_status nvm_update(nvm_t *h_nvm, uint32_t addr, uint8_t *p_buf, uint32_t size);



#endif

